﻿using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Linq;
using System.Text;
using System.IO;

namespace QW.Core.Encrypt
{
    /// <summary>
    /// DES加密解密工具
    /// </summary>
    public sealed class DESHelper
    {
        #region 加密
        /// <summary>
        /// DES-CBC-PKCS7 加密
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static byte[] Encrypt(byte[] str, byte[] key, byte[] iv)
        {
            DESCryptoServiceProvider provider = new DESCryptoServiceProvider
            {
                Key = key,
                Padding = PaddingMode.PKCS7,
                Mode = CipherMode.CBC
            };
            if (iv != null)
            {
                provider.IV = iv;
            }
            MemoryStream mStream = new MemoryStream();
            CryptoStream cStream = new CryptoStream(mStream, provider.CreateEncryptor(), CryptoStreamMode.Write);
            cStream.Write(str, 0, str.Length);
            cStream.FlushFinalBlock();
            return mStream.ToArray();
        }
        /// <summary>
        /// DES-CBC-PKCS7 加密(返回16进制结果)
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key">密钥，8位</param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string Encrypt(string str, string key = ConstData.DEFAULT_KEY, Encoding encode = null)
        {
            if (string.IsNullOrEmpty(str)) return null;
            if (encode == null)
            {
                encode = Encoding.UTF8;
            }
            if (key.Length > 8)
            {
                key = key.Substring(8);
            }
            key = key.PadRight(8, '0');
            byte[] keyBytes = encode.GetBytes(key);
            byte[] keyIV = keyBytes;
            byte[] arr_str = encode.GetBytes(str);
            var arr_result = Encrypt(arr_str, keyBytes, keyIV);
            StringBuilder sb = new StringBuilder(50);
            foreach (byte b in arr_result)
            {
                sb.AppendFormat("{0:x2}", b);
            }
            return sb.ToString();
        }
        /// <summary>
        /// DES-CBC-PKCS7 加密(返回Base64结果)
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key">密钥，8位</param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string EncryptToBase64(string str, string key = ConstData.DEFAULT_KEY, Encoding encode = null)
        {
            if (string.IsNullOrEmpty(str)) return null;
            if (encode == null)
            {
                encode = Encoding.UTF8;
            }
            if (key.Length > 8)
            {
                key = key.Substring(8);
            }
            key = key.PadRight(8, '0');
            byte[] keyBytes = encode.GetBytes(key);
            byte[] keyIV = keyBytes;
            byte[] arr_str = encode.GetBytes(str);
            var arr_result = Encrypt(arr_str, keyBytes, keyIV);
            return Convert.ToBase64String(arr_result);
        }
        #endregion

        #region 解密
        /// <summary>
        /// DES-CBC-PKCS7 解密
        /// </summary>
        /// <param name="str"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static byte[] Decrypt(byte[] str, byte[] key, byte[] iv)
        {
            DESCryptoServiceProvider provider = new DESCryptoServiceProvider
            {
                Key = key,
                Padding = PaddingMode.PKCS7,
                Mode = CipherMode.CBC
            };
            if (iv != null)
            {
                provider.IV = iv;
            }
            MemoryStream mStream = new MemoryStream();
            CryptoStream cStream = new CryptoStream(mStream, provider.CreateDecryptor(), CryptoStreamMode.Write);
            cStream.Write(str, 0, str.Length);
            cStream.FlushFinalBlock();
            return mStream.ToArray();
        }
        /// <summary>
        /// DES-CBC-PKCS7 解密
        /// </summary>
        /// <param name="str">Base64字符</param>
        /// <param name="key">密钥，8位</param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string DecryptFromBase64(string str, string key = ConstData.DEFAULT_KEY, Encoding encode = null)
        {
            if (string.IsNullOrEmpty(str)) return null;
            if (encode == null)
            {
                encode = Encoding.UTF8;
            }

            if (key.Length > 8)
            {
                key = key.Substring(8);
            }
            key = key.PadRight(8, '0');

            byte[] keyBytes = encode.GetBytes(key);
            byte[] keyIV = keyBytes;
            byte[] arr_str = Convert.FromBase64String(str);
            var arr_result = Decrypt(arr_str, keyBytes, keyIV);
            return encode.GetString(arr_result).Replace("\0", ""); ;
        }
        /// <summary>
        /// DES-CBC-PKCS7 解密
        /// </summary>
        /// <param name="str">16进制字符</param>
        /// <param name="key">密钥，8位</param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string Decrypt(string str, string key = ConstData.DEFAULT_KEY, Encoding encode = null)
        {
            if (string.IsNullOrEmpty(str)) return null;
            if (encode == null)
            {
                encode = Encoding.UTF8;
            }
            if (key.Length > 8)
            {
                key = key.Substring(8);
            }
            key = key.PadRight(8, '0');

            byte[] keyBytes = encode.GetBytes(key);
            byte[] keyIV = keyBytes;
            List<byte> lstBytes = new List<byte>();
            for (int i = 0; i < str.Length; i += 2)
            {
                lstBytes.Add(Convert.ToByte(str.Substring(i, 2), 16));
            }
            byte[] str_arr = lstBytes.ToArray();
            var arr_result = Decrypt(str_arr, keyBytes, keyIV);
            return encode.GetString(arr_result).Replace("\0", ""); ;
        }
        #endregion
    }
}
